// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Author: Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
//         Basile Bougenot <bbougenot@student.ethz.ch>
//         Matteo Perotti <mperotti@iis.ee.ethz.ch>

#include "vector_macros.h"
#include "float_macros.h"

// Simple random test with similar values
void TEST_CASE1(void) {
  VSET(16, e16, m1);
  //              -93.0000, -55.1250, -68.5625,  76.3125, -61.2188,  48.9375, -56.3125,  71.0000, -74.5625, -38.7188, -50.3438,  93.3750,  80.2500, -7.4141,  93.8125,  83.1875
  VLOAD_16(v2,     0xd5d0,  0xd2e4,  0xd449,  0x54c5,  0xd3a7,  0x521e,  0xd30a,  0x5470,  0xd4a9,  0xd0d7,  0xd24b,  0x55d6,  0x5504,  0xc76a,  0x55dd,  0x5533);
  //              -60.0312, -31.7188, -74.2500, -0.9077,  30.4844, -56.2500, -4.8320,  34.2812,  66.6875,  37.9375,  78.1875,  5.6094, -81.8125,  67.6250,  29.4531, -64.9375
  VLOAD_16(v6,     0xd381,  0xcfee,  0xd4a4,  0xbb43,  0x4f9f,  0xd308,  0xc4d5,  0x5049,  0x542b,  0x50be,  0x54e3,  0x459c,  0xd51d,  0x543a,  0x4f5d,  0xd40f);
  //               31.29529381, -66.12346649, -48.59321213,  21.66906929,  92.08473206,  1.95985305, -96.55027771,  77.65225220, -82.48660278, -35.32508850,  42.91923141, -76.65069580,  25.13817024,  72.89311981,  21.44047737,  69.71634674
  VLOAD_32(v4,     0x41fa5cc3,  0xc2843f37,  0xc2425f73,  0x41ad5a41,  0x42b82b62,  0x3ffadc77,  0xc2c119be,  0x429b4df4,  0xc2a4f924,  0xc20d4ce4,  0x422bad4b,  0xc2994d28,  0x41c91af9,  0x4291c947,  0x41ab8619,  0x428b6ec5);
  asm volatile("vfwmsac.vv v4, v2, v6");
  //               5551.61083984,  1814.61950684,  5139.35888672, -90.93905640, -1958.30004883, -2754.69433594,  368.65405273,  2356.31640625, -4889.89990234, -1433.56750488, -3979.17114258,  600.42608643, -6590.59130859, -574.26910400,  2741.63085938, -5471.70458984
  VCMP_U32(1, v4,  0x45ad7ce3,  0x44e2d3d3,  0x45a09adf,  0xc2b5e0cc,  0xc4f4c99a,  0xc52c2b1c,  0x43b853b8,  0x45134510,  0xc598cf33,  0xc4b33229,  0xc578b2bd,  0x44161b45,  0xc5cdf4bb,  0xc40f9139,  0x452b5a18,  0xc5aafda3);

  VSET(16, e32, m1);
  //              -71423.96093750, -46625.21875000, -59851.39453125, -43461.99218750, -10255.72753906,  37671.59765625,  96842.05468750,  33293.05859375,  27126.79296875, -27343.42187500,  26815.15429688,  28654.72070312, -5699.91699219,  70582.03906250, -5936.72802734,  43479.90234375
  VLOAD_32(v2,     0xc78b7ffb,  0xc7362138,  0xc769cb65,  0xc729c5fe,  0xc6203ee9,  0x47132799,  0x47bd2507,  0x47020d0f,  0x46d3ed96,  0xc6d59ed8,  0x46d17e4f,  0x46dfdd71,  0xc5b21f56,  0x4789db05,  0xc5b985d3,  0x4729d7e7);
  //               93657.15625000, -28369.10156250, -42169.91406250, -21377.95507812,  16308.38183594,  64517.84375000, -12469.71679688, -76994.53125000, -33687.83593750, -84006.54687500,  31506.48437500,  2731.77905273, -20272.41992188,  53550.01953125, -85441.62500000, -33418.07031250
  VLOAD_32(v6,     0x47b6ec94,  0xc6dda234,  0xc724b9ea,  0xc6a703e9,  0x467ed187,  0x477c05d8,  0xc642d6de,  0xc7966144,  0xc70397d6,  0xc7a41346,  0x46f624f8,  0x452abc77,  0xc69e60d7,  0x47512e05,  0xc7a6e0d0,  0xc7028a12);
  //               15054.1952512034331448, -39042.3922682931588497, -83554.3539477824524511,  35787.9235785690543707, -34715.2784411938628182,  35880.5352577352605294, -52433.9701052222590079, -40831.3148960549369804, -3569.6808186589187244,  77018.1414445060363505,  58906.1301468654128257, -84146.7844421620393405, -23969.5482366856886074,  92255.7186088700836990, -35519.3091108352309675, -65623.9480113173485734
  VLOAD_64(v4,     0x40cd6718fdfdcea0,  0xc0e3104c8d763c4c,  0xc0f46625a9c52662,  0x40e1797d8df4a4ac,  0xc0e0f368e8fd81b0,  0x40e1851120d4d47c,  0xc0e99a3f0b1a1b69,  0xc0e3efea13a0e433,  0xc0abe35c94436520,  0x40f2cda2435b507a,  0x40ecc3442a29c254,  0xc0f48b2c8d133979,  0xc0d76863164f52e0,  0x40f685fb7f6c03ba,  0xc0e157e9e43c6805,  0xc0f0057f2b0dea44);
  asm volatile("vfwmsac.vv v4, v2, v6");
  //              -6689380123.7125854492187500,  1322754608.4847974777221680,  2524011718.2575426101684570,  929092728.6666160821914673, -167219605.4339296817779541,  2430454370.8635458946228027, -1207540562.0105009078979492, -2563342608.9896693229675293, -913839381.3609598875045776,  2296949433.3236432075500488,  844792333.7375594377517700,  78362512.5631930530071259,  115575080.3336923867464066,  3779577314.6337165832519531,  507279209.1484052538871765, -1452948809.7560596466064453
  VCMP_U64(2, v4,  0xc1f8eb7d71bb66c0,  0x41d3b5e88c1f06ec,  0x41e2ce2b98c83dca,  0x41cbb06a3c5553ad,  0xc1a3ef232ade2c08,  0x41e21bb94c5ba22b,  0xc1d1fe66d480ac0c,  0xc1e31930221fab5f,  0xc1cb3c0a8aae33ef,  0x41e11d15572a5b49,  0x41c92d4106de6859,  0x4192aede4240b5ae,  0x419b8e24a155b375,  0x41ec28f8bc544768,  0x41be3c776925fde3,  0xc1d5a68f52706348);
};

// Simple random test with similar values (masked)
// The numbers are the same of TEST_CASE1
void TEST_CASE2(void) {
  VSET(16, e16, m1);
  //              -93.0000, -55.1250, -68.5625,  76.3125, -61.2188,  48.9375, -56.3125,  71.0000, -74.5625, -38.7188, -50.3438,  93.3750,  80.2500, -7.4141,  93.8125,  83.1875
  VLOAD_16(v2,     0xd5d0,  0xd2e4,  0xd449,  0x54c5,  0xd3a7,  0x521e,  0xd30a,  0x5470,  0xd4a9,  0xd0d7,  0xd24b,  0x55d6,  0x5504,  0xc76a,  0x55dd,  0x5533);
  //              -60.0312, -31.7188, -74.2500, -0.9077,  30.4844, -56.2500, -4.8320,  34.2812,  66.6875,  37.9375,  78.1875,  5.6094, -81.8125,  67.6250,  29.4531, -64.9375
  VLOAD_16(v6,     0xd381,  0xcfee,  0xd4a4,  0xbb43,  0x4f9f,  0xd308,  0xc4d5,  0x5049,  0x542b,  0x50be,  0x54e3,  0x459c,  0xd51d,  0x543a,  0x4f5d,  0xd40f);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               31.29529381, -66.12346649, -48.59321213,  21.66906929,  92.08473206,  1.95985305, -96.55027771,  77.65225220, -82.48660278, -35.32508850,  42.91923141, -76.65069580,  25.13817024,  72.89311981,  21.44047737,  69.71634674
  VLOAD_32(v4,     0x41fa5cc3,  0xc2843f37,  0xc2425f73,  0x41ad5a41,  0x42b82b62,  0x3ffadc77,  0xc2c119be,  0x429b4df4,  0xc2a4f924,  0xc20d4ce4,  0x422bad4b,  0xc2994d28,  0x41c91af9,  0x4291c947,  0x41ab8619,  0x428b6ec5);
  asm volatile("vfwmsac.vv v4, v2, v6, v0.t");
  //               31.29529381,  1814.61950684, -48.59321213, -90.93905640,  92.08473206, -2754.69433594, -96.55027771,  2356.31640625, -82.48660278, -1433.56750488,  42.91923141,  600.42608643,  25.13817024, -574.26910400,  21.44047737, -5471.70458984
  VCMP_U32(3, v4,  0x41fa5cc3,  0x44e2d3d3,  0xc2425f73,  0xc2b5e0cc,  0x42b82b62,  0xc52c2b1c,  0xc2c119be,  0x45134510,  0xc2a4f924,  0xc4b33229,  0x422bad4b,  0x44161b45,  0x41c91af9,  0xc40f9139,  0x41ab8619,  0xc5aafda3);

  VSET(16, e32, m1);
  //              -71423.96093750, -46625.21875000, -59851.39453125, -43461.99218750, -10255.72753906,  37671.59765625,  96842.05468750,  33293.05859375,  27126.79296875, -27343.42187500,  26815.15429688,  28654.72070312, -5699.91699219,  70582.03906250, -5936.72802734,  43479.90234375
  VLOAD_32(v2,     0xc78b7ffb,  0xc7362138,  0xc769cb65,  0xc729c5fe,  0xc6203ee9,  0x47132799,  0x47bd2507,  0x47020d0f,  0x46d3ed96,  0xc6d59ed8,  0x46d17e4f,  0x46dfdd71,  0xc5b21f56,  0x4789db05,  0xc5b985d3,  0x4729d7e7);
  //               93657.15625000, -28369.10156250, -42169.91406250, -21377.95507812,  16308.38183594,  64517.84375000, -12469.71679688, -76994.53125000, -33687.83593750, -84006.54687500,  31506.48437500,  2731.77905273, -20272.41992188,  53550.01953125, -85441.62500000, -33418.07031250
  VLOAD_32(v6,     0x47b6ec94,  0xc6dda234,  0xc724b9ea,  0xc6a703e9,  0x467ed187,  0x477c05d8,  0xc642d6de,  0xc7966144,  0xc70397d6,  0xc7a41346,  0x46f624f8,  0x452abc77,  0xc69e60d7,  0x47512e05,  0xc7a6e0d0,  0xc7028a12);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               15054.1952512034331448, -39042.3922682931588497, -83554.3539477824524511,  35787.9235785690543707, -34715.2784411938628182,  35880.5352577352605294, -52433.9701052222590079, -40831.3148960549369804, -3569.6808186589187244,  77018.1414445060363505,  58906.1301468654128257, -84146.7844421620393405, -23969.5482366856886074,  92255.7186088700836990, -35519.3091108352309675, -65623.9480113173485734
  VLOAD_64(v4,     0x40cd6718fdfdcea0,  0xc0e3104c8d763c4c,  0xc0f46625a9c52662,  0x40e1797d8df4a4ac,  0xc0e0f368e8fd81b0,  0x40e1851120d4d47c,  0xc0e99a3f0b1a1b69,  0xc0e3efea13a0e433,  0xc0abe35c94436520,  0x40f2cda2435b507a,  0x40ecc3442a29c254,  0xc0f48b2c8d133979,  0xc0d76863164f52e0,  0x40f685fb7f6c03ba,  0xc0e157e9e43c6805,  0xc0f0057f2b0dea44);
  asm volatile("vfwmsac.vv v4, v2, v6, v0.t");
  //               15054.1952512034331448,  1322754608.4847974777221680, -83554.3539477824524511,  929092728.6666160821914673, -34715.2784411938628182,  2430454370.8635458946228027, -52433.9701052222590079, -2563342608.9896693229675293, -3569.6808186589187244,  2296949433.3236432075500488,  58906.1301468654128257,  78362512.5631930530071259, -23969.5482366856886074,  3779577314.6337165832519531, -35519.3091108352309675, -1452948809.7560596466064453
  VCMP_U64(4, v4,  0x40cd6718fdfdcea0,  0x41d3b5e88c1f06ec,  0xc0f46625a9c52662,  0x41cbb06a3c5553ad,  0xc0e0f368e8fd81b0,  0x41e21bb94c5ba22b,  0xc0e99a3f0b1a1b69,  0xc1e31930221fab5f,  0xc0abe35c94436520,  0x41e11d15572a5b49,  0x40ecc3442a29c254,  0x4192aede4240b5ae,  0xc0d76863164f52e0,  0x41ec28f8bc544768,  0xc0e157e9e43c6805,  0xc1d5a68f52706348);
};

// Simple random test with similar values (vector-scalar)
void TEST_CASE3(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //               8.1562,  2.6836,  56.7188,  38.4688,  33.8125, -83.0625,  37.7812, -28.0938, -33.0625,  61.1562,  13.0859, -80.5000,  78.3125, -38.0625,  30.0625, -78.6250
  VLOAD_16(v2,     0x4814,  0x415e,  0x5317,  0x50cf,  0x503a,  0xd531,  0x50b9,  0xcf06,  0xd022,  0x53a5,  0x4a8b,  0xd508,  0x54e5,  0xd0c2,  0x4f84,  0xd4ea);
  //                              39.8125
  BOX_HALF_IN_DOUBLE(dscalar_16,  0x50fa);
  //               56.66989136,  59.83663559, -8.21133614, -19.17305374, -93.35797119, -34.25491333,  46.99548721, -6.17113161,  55.22229004,  7.96844339, -92.84493256, -90.90106201,  78.59468842, -58.67407608,  39.90958405, -93.58789825
  VLOAD_32(v4,     0x4262adf8,  0x426f58b7,  0xc10361a2,  0xc199626a,  0xc2bab748,  0xc2090508,  0x423bfb61,  0xc0c579e9,  0x425ce3a0,  0x40fefd7d,  0xc2b9b09b,  0xc2b5cd58,  0x429d307b,  0xc26ab241,  0x421fa36a,  0xc2bb2d01);
  asm volatile("vfwmsac.vf v4, %[A], v2" :: [A] "f" (dscalar_16));
  //               268.05081177,  47.00394058,  2266.32666016,  1550.71020508,  1439.51806641, -3272.67089844,  1457.17053223, -1112.31127930, -1371.52307129,  2426.81469727,  613.82879639, -3114.00512695,  3039.22167969, -1456.68920898,  1156.95373535, -3036.66992188
  VCMP_U32(5, v4,  0x43860681,  0x423c0409,  0x450da53a,  0x44c1d6ba,  0x44b3f094,  0xc54c8abc,  0x44b62575,  0xc48b09f6,  0xc4ab70bd,  0x4517ad09,  0x4419750b,  0xc542a015,  0x453df38c,  0xc4b6160e,  0x44909e85,  0xc53dcab8);

  VSET(16, e32, m1);
  double dscalar_32;
  //               580253.06250000, -300331.93750000,  485801.21875000, -751037.87500000, -360868.65625000,  893035.68750000,  541162.00000000,  417622.93750000, -933287.18750000, -790074.12500000,  496987.96875000,  455066.96875000, -928285.18750000,  300725.40625000, -645096.93750000,  102530.55468750
  VLOAD_32(v2,     0x490da9d1,  0xc892a57e,  0x48ed3527,  0xc9375bde,  0xc8b03495,  0x495a06bb,  0x49041ea0,  0x48cbeade,  0xc963da73,  0xc940e3a2,  0x48f2ab7f,  0x48de335f,  0xc962a1d3,  0x4892d6ad,  0xc91d7e8f,  0x47c84147);
  //                               670995.56250000
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0x4923d139);
  //               579132.0708449089433998,  521241.3016625398304313,  409779.0302067114971578,  454935.4394149139989167, -640831.0776052488945425,  262502.9360184965189546, -132061.7241549796890467, -523289.4277524493518285,  796635.9535234714858234,  170970.3947326899506152, -520724.0386287728324533, -616193.5881990450434387,  79952.4583538805600256, -869849.3916852036491036,  535808.2751473840326071, -306070.6657954099355265
  VLOAD_64(v4,     0x4121ac782445c8ae,  0x411fd06534e7065c,  0x411902cc1eee8218,  0x411bc45dc1f5fbb4,  0xc1238e7e27bbe00c,  0x4110059bbe7ba1fc,  0xc1001eedcb11c418,  0xc11ff065b604bcf3,  0x41284fb7e8343a7c,  0x4104ded328699cd0,  0xc11fc850278e4d10,  0xc122ce032d286cdc,  0x40f38507556ae0f0,  0xc12a8bb2c88af688,  0x41205a008ce01e30,  0xc112ae5aa9c6459e);
  asm volatile("vfwmsac.vf v4, %[A], v2" :: [A] "f" (dscalar_32));
  //               389346650932.4642944335937500, -201521918580.8290100097656250,  325970052259.3115844726562500, -503943536329.8690795898437500, -242140626158.0102844238281250,  599222720963.7006835937500000,  363117432655.3491821289062500,  280223661150.1425781250000000, -626232357986.5589599609375000, -530136402891.4650268554687500,  333477242371.1773071289062500,  305348532865.1643676757812500, -622875321499.4388427734375000,  201786282974.1514587402343750, -432857718253.1149902343750000,  68797853286.6418762207031250
  VCMP_U64(6, v4,  0x4256a9b79acd1db7,  0xc24775d2393a6a1d,  0x4252f9551128d3f1,  0xc25d555807b2779f,  0xc24c305a5e770151,  0x4261708ea338766c,  0x425522df13d3d659,  0x42504fa86f178920,  0xc26239cb6e8c51e3,  0xc25edba5e2f2ddc3,  0x42536932b980cb59,  0x4251c60c36a04a85,  0xc26220c864936e0b,  0x42477db329ef1363,  0xc2593215277b475c,  0x423004abee66a452);
};

// Simple random test with similar values (vector-scalar) (masked)
void TEST_CASE4(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //                8.1562,  2.6836,  56.7188,  38.4688,  33.8125, -83.0625,  37.7812, -28.0938, -33.0625,  61.1562,  13.0859, -80.5000,  78.3125, -38.0625,  30.0625, -78.6250
  VLOAD_16(v2,      0x4814,  0x415e,  0x5317,  0x50cf,  0x503a,  0xd531,  0x50b9,  0xcf06,  0xd022,  0x53a5,  0x4a8b,  0xd508,  0x54e5,  0xd0c2,  0x4f84,  0xd4ea);
  //                              39.8125
  BOX_HALF_IN_DOUBLE(dscalar_16,  0x50fa);
  VLOAD_8(v0, 0xAA, 0xAA);
  //                56.66989136,  59.83663559, -8.21133614, -19.17305374, -93.35797119, -34.25491333,  46.99548721, -6.17113161,  55.22229004,  7.96844339, -92.84493256, -90.90106201,  78.59468842, -58.67407608,  39.90958405, -93.58789825
  VLOAD_32(v4,      0x4262adf8,  0x426f58b7,  0xc10361a2,  0xc199626a,  0xc2bab748,  0xc2090508,  0x423bfb61,  0xc0c579e9,  0x425ce3a0,  0x40fefd7d,  0xc2b9b09b,  0xc2b5cd58,  0x429d307b,  0xc26ab241,  0x421fa36a,  0xc2bb2d01);
  asm volatile("vfwmsac.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_16));
  //                56.66989136,  47.00394058, -8.21133614,  1550.71020508, -93.35797119, -3272.67089844,  46.99548721, -1112.31127930,  55.22229004,  2426.81469727, -92.84493256, -3114.00512695,  78.59468842, -1456.68920898,  39.90958405, -3036.66992188
  VCMP_U32(7, v4,  0x4262adf8,  0x423c0409,  0xc10361a2,  0x44c1d6ba,  0xc2bab748,  0xc54c8abc,  0x423bfb61,  0xc48b09f6,  0x425ce3a0,  0x4517ad09,  0xc2b9b09b,  0xc542a015,  0x429d307b,  0xc4b6160e,  0x421fa36a,  0xc53dcab8);

  VSET(16, e32, m1);
  double dscalar_32;
  //                580253.06250000, -300331.93750000,  485801.21875000, -751037.87500000, -360868.65625000,  893035.68750000,  541162.00000000,  417622.93750000, -933287.18750000, -790074.12500000,  496987.96875000,  455066.96875000, -928285.18750000,  300725.40625000, -645096.93750000,  102530.55468750
  VLOAD_32(v2,      0x490da9d1,  0xc892a57e,  0x48ed3527,  0xc9375bde,  0xc8b03495,  0x495a06bb,  0x49041ea0,  0x48cbeade,  0xc963da73,  0xc940e3a2,  0x48f2ab7f,  0x48de335f,  0xc962a1d3,  0x4892d6ad,  0xc91d7e8f,  0x47c84147);
  //                               670995.56250000
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0x4923d139);
  VLOAD_8(v0, 0xAA, 0xAA);
  //                579132.0708449089433998,  521241.3016625398304313,  409779.0302067114971578,  454935.4394149139989167, -640831.0776052488945425,  262502.9360184965189546, -132061.7241549796890467, -523289.4277524493518285,  796635.9535234714858234,  170970.3947326899506152, -520724.0386287728324533, -616193.5881990450434387,  79952.4583538805600256, -869849.3916852036491036,  535808.2751473840326071, -306070.6657954099355265
  VLOAD_64(v4,      0x4121ac782445c8ae,  0x411fd06534e7065c,  0x411902cc1eee8218,  0x411bc45dc1f5fbb4,  0xc1238e7e27bbe00c,  0x4110059bbe7ba1fc,  0xc1001eedcb11c418,  0xc11ff065b604bcf3,  0x41284fb7e8343a7c,  0x4104ded328699cd0,  0xc11fc850278e4d10,  0xc122ce032d286cdc,  0x40f38507556ae0f0,  0xc12a8bb2c88af688,  0x41205a008ce01e30,  0xc112ae5aa9c6459e);
  asm volatile("vfwmsac.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_32));
  //                579132.0708449089433998, -201521918580.8290100097656250,  409779.0302067114971578, -503943536329.8690795898437500, -640831.0776052488945425,  599222720963.7006835937500000, -132061.7241549796890467,  280223661150.1425781250000000,  796635.9535234714858234, -530136402891.4650268554687500, -520724.0386287728324533,  305348532865.1643676757812500,  79952.4583538805600256,  201786282974.1514587402343750,  535808.2751473840326071,  68797853286.6418762207031250
  VCMP_U64(8, v4,  0x4121ac782445c8ae,  0xc24775d2393a6a1d,  0x411902cc1eee8218,  0xc25d555807b2779f,  0xc1238e7e27bbe00c,  0x4261708ea338766c,  0xc1001eedcb11c418,  0x42504fa86f178920,  0x41284fb7e8343a7c,  0xc25edba5e2f2ddc3,  0xc11fc850278e4d10,  0x4251c60c36a04a85,  0x40f38507556ae0f0,  0x42477db329ef1363,  0x41205a008ce01e30,  0x423004abee66a452);
};

int main(void) {
  enable_vec();
  enable_fp();

  TEST_CASE1();
  TEST_CASE2();
  TEST_CASE3();
  TEST_CASE4();

  EXIT_CHECK();
}

